package org.bozo.im.service.protocols.xmpp;

import java.io.IOException;
import java.net.Socket;
import java.util.Hashtable;

import javax.net.SocketFactory;

import org.bozo.im.service.Constants;
import org.bozo.im.service.IMSession;
import org.bozo.im.service.IMSessionConfiguration;
import org.bozo.im.service.protocols.xmpp.session.XMPPReader;
import org.bozo.im.service.protocols.xmpp.session.XMPPTaskProcessor;
import org.bozo.im.service.protocols.xmpp.session.XMPPWriter;
import org.bozo.im.service.protocols.xmpp.stanza.Stanza;
import org.bozo.im.service.protocols.xmpp.stanza.processor.StanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.bind.BindStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.bind.JidStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.error.ErrorStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.error.TextStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.jabber.client.IqStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.jabber.client.PresenceStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.roster.ItemStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.roster.QueryStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.sasl.ChallengeStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.sasl.MechanismStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.sasl.MechanismsStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.sasl.SuccessStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.session.SessionStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.starttls.ProceedStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.starttls.RequiredStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.starttls.StartTlsStanzaProcessor;
import org.bozo.im.service.protocols.xmpp.stanza.processor.stream.FeaturesStanzaProcessor;
import org.xmlpull.v1.XmlPullParserException;

import android.util.Log;

public class XMPPSession extends IMSession {

	// ---------------------------------------------------------------------------------------
	// Variables
	// ---------------------------------------------------------------------------------------

	private XMPPSessionConfiguration mConfiguration;

	private Socket mSocket;

	private XMPPWriter mWriter;
	private XMPPReader mReader;
	private XMPPTaskProcessor mTasks;

	private int mId = 1;

	// ---------------------------------------------------------------------------------------
	// Constructor
	// ---------------------------------------------------------------------------------------

	public XMPPSession(IMSessionConfiguration pConfiguration) {
		super(pConfiguration);

		if (pConfiguration instanceof XMPPSessionConfiguration)
			mConfiguration = (XMPPSessionConfiguration)pConfiguration;

		mStanzas = new Hashtable<Stanza, StanzaProcessor>();

		// Bind stanzas
		addStanza(BindStanzaProcessor.getInstance());
		addStanza(JidStanzaProcessor.getInstance());

		// Error stanzas
		addStanza(ErrorStanzaProcessor.getInstance());
		addStanza(TextStanzaProcessor.getInstance());

		// Roster stanzas
		addStanza(ItemStanzaProcessor.getInstance());
		addStanza(QueryStanzaProcessor.getInstance());

		// Jabber client stanzas
		addStanza(IqStanzaProcessor.getInstance());
		addStanza(PresenceStanzaProcessor.getInstance());

		// Sasl stanzas
		addStanza(ChallengeStanzaProcessor.getInstance());
		addStanza(MechanismsStanzaProcessor.getInstance());
		addStanza(MechanismStanzaProcessor.getInstance());
		addStanza(SuccessStanzaProcessor.getInstance());

		// Session stanzas
		addStanza(SessionStanzaProcessor.getInstance());

		// Starttls stanzas
		addStanza(ProceedStanzaProcessor.getInstance());
		addStanza(RequiredStanzaProcessor.getInstance());
		addStanza(StartTlsStanzaProcessor.getInstance());

		// Stream stanzas
		addStanza(FeaturesStanzaProcessor.getInstance());
	}

	// ---------------------------------------------------------------------------------------
	// ID related methods
	// ---------------------------------------------------------------------------------------

	public String getId() {
		return String.valueOf(mId++);
	}

	// ---------------------------------------------------------------------------------------
	// Stanzas related methods
	// ---------------------------------------------------------------------------------------

	private Hashtable<Stanza, StanzaProcessor> mStanzas;

	private void addStanza(StanzaProcessor pStanza) {
		mStanzas.put(pStanza.getStanza(), pStanza);
	}

	public StanzaProcessor getStanza(Stanza pStanza) {

		StanzaProcessor lRes = null;

		if (pStanza != null)
			lRes = mStanzas.get(pStanza);

		return lRes;
	}

	// ---------------------------------------------------------------------------------------
	// Sessions related methods
	// ---------------------------------------------------------------------------------------

	@Override
	public void startSession() throws XmlPullParserException, IOException {

		// ---------------------------------------------------------------------------------------
		Log.d(Constants.ACTIVITY_TAG, "org.bozo.im.xmpp.session.Session.startSession ---------- IN");
		// ---------------------------------------------------------------------------------------

		if (mSocket == null) {
			mSocket = SocketFactory.getDefault().createSocket(mConfiguration.getServer(), mConfiguration.getPort());
			mSocket.setSoTimeout(0);
			mSocket.setKeepAlive(true);

			mWriter = new XMPPWriter(this, mSocket);
			mReader = new XMPPReader(this, mSocket);
			mTasks = new XMPPTaskProcessor(this);

			mReader.startListener();
			mWriter.writeHeader();
		}

		mWriter.startStream();

		// ---------------------------------------------------------------------------------------
		Log.d(Constants.ACTIVITY_TAG, "org.bozo.im.xmpp.session.Session.startSession ---------- OUT");
		// ---------------------------------------------------------------------------------------
	}

	@Override
	public void stopSession() throws Exception {
		mWriter.closeStream();
		mSocket.close();
	}

	public XMPPSessionConfiguration getConfiguration() {
		return mConfiguration;
	}

	// ---------------------------------------------------------------------------------------
	// Sockets related methods
	// ---------------------------------------------------------------------------------------

	public Socket getSocket() {
		return mSocket;
	}

	public void setSocket(Socket pSocket) throws IOException, XmlPullParserException {
		mSocket = pSocket;
		getReader().updateSocket(mSocket);
		getWriter().updateSocket(mSocket);
	}

	public XMPPReader getReader() {
		return mReader;
	}

	public XMPPWriter getWriter() {
		return mWriter;
	}

	public XMPPTaskProcessor getTaskProcessor() {
		return mTasks;
	}


}
